/*内核模块程序——阻塞IO*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>

#include "button.h"


/*定义结构体类型*/
struct rk3399_button
{
	unsigned int major;
	struct class* pcls;
	struct device* pdev;
	unsigned int gpio;
	int irq;
	struct BUTTON button;
	wait_queue_head_t wqhead;
	int condition;
};

/*全局变量*/
static struct rk3399_button* pbutton;//声明结构体指针，但没分配结构体变量空间

static const struct platform_device_id button_id_table[] = 
{
	{ .name = "rk3399_button", .driver_data = 0x1 }, 
	{ .name = "rk3288_button", .driver_data = 0x2 }, 
	{ .name = "rk3568_button", .driver_data = 0x3 },
};


/*中断处理函数*/
static irqreturn_t button_handler(int irq, void *dev_id)
{
	int value;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*读取GPIO口电平状态*/
	pbutton->button.code = 'A';
	value = gpio_get_value(pbutton->gpio);
	if(value)
		pbutton->button.value = 0;//高电平是松开状态
	else
		pbutton->button.value = 1;//低电平是按下状态

	/*唤醒休眠进程*/
	pbutton->condition = 1;
	wake_up_interruptible(&pbutton->wqhead);
	
	return IRQ_HANDLED;
}

/*定义系统调用接口*/
static int button_open (struct inode *inode, struct file *filp)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return 0;
}

static int button_close (struct inode *inode, struct file *filp)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return 0;
}

static ssize_t button_read(struct file *filp, char __user *buf, size_t size, loff_t *flag)
{
	int ret;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*阻塞，直到条件成立——按钮按下或松开*/
	wait_event_interruptible(pbutton->wqhead,pbutton->condition);

	/*把按键状态拷贝到用户空间*/
	ret = copy_to_user(buf, &pbutton->button, sizeof(struct BUTTON));
	if(ret > 0)
	{
		printk("<kernel>copy_to_user fail.\n");
		return -EFAULT;
	}	

	/*重置按键信息和条件变量*/
	pbutton->button.code = 'X';
	pbutton->condition = 0;
	
	return sizeof(struct BUTTON);
}

static ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flag)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	return size;
}

/*改变系统调用接口地址*/
static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = button_open,
	.release = button_close,
	.read = button_read,
	.write = button_write,
};

/*定义probe、remove函数*/
static int button_probe(struct platform_device *pdev)
{
	int ret;
	struct button_platform_data* pdata = NULL;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*获取平台数据*/
	
	pdata = (struct button_platform_data*)pdev->dev.platform_data; 
	if (!pdata) //如果pdata为空指针
	{
		printk("<kernel>button_platform_data get fail\n");
		return -EFAULT;
	}

	/*申请分配结构体空间*/
	pbutton = kmalloc(sizeof(struct rk3399_button), GFP_KERNEL);
	if(pbutton == NULL)
	{
		printk("kmalloc fail\n");
		return -ENOMEM;
	}

	/*初始化按键信息*/
	pbutton->button.code = 'X';
	pbutton->button.value = 0;	

	/*注册主设备号（动态）*/
	pbutton->major = register_chrdev(0, "button_drv", &fops);
	if(pbutton->major < 0)
	{
		printk("<kernel>register major fail.\n");
		ret = -EBUSY;
		goto err_register_chrdev;
	}
	printk("<kernel>register major success!\n");
	printk("<kernel>major = %d\n",pbutton->major);

	/*创建设备类*/
	pbutton->pcls = class_create(THIS_MODULE, "button_cls");
	if (IS_ERR(pbutton->pcls))
	{
		ret = PTR_ERR(pbutton->pcls);
		goto err_class_create;
	}

	/*创建设备文件*/
	pbutton->pdev = device_create(pbutton->pcls,NULL, MKDEV(pbutton->major, 123),NULL,"button");
	if (IS_ERR(pbutton->pdev))
	{
		ret = PTR_ERR(pbutton->pdev);
		goto err_device_create;
	} 

	/*初始化硬件*/
	pbutton->gpio = pdata->pbutton_gpio[0].gpio;//获取按键的引脚号
	ret = gpio_request(pbutton->gpio, pdata->pbutton_gpio[0].desc);
	if (ret) 
	{
		printk("gpio_request fail\n");
		ret = -EFAULT;
		goto err_gpio_request;
	}
	gpio_direction_input(pbutton->gpio);//将按键IO口设置为输入方向
	gpio_free(pbutton->gpio);

	/*获取中断号*/
	pbutton->irq = gpio_to_irq(pbutton->gpio);
	printk("<kernel>irq:%d\n",pbutton->irq);

	/*申请中断*/
	ret = request_irq(pbutton->irq, button_handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, 
			"pwr_interrupt", NULL);//双边沿都能触发中断
	if (ret < 0) 
	{
		printk("request_irq fail\n");
		ret = -EINVAL;
		goto err_request_irq;
	} 

	/*初始化等待队列头*/
	init_waitqueue_head(&pbutton->wqhead);
	pbutton->condition = 0;//初始时默认条件不成立

	return 0;

	/*集中容错处理*/
err_request_irq:
	gpio_free(pbutton->gpio);
err_gpio_request:
	device_destroy(pbutton->pcls, MKDEV(pbutton->major, 123));
err_device_create:
	class_destroy(pbutton->pcls);
err_class_create:
	unregister_chrdev(pbutton->major, "button_drv");
err_register_chrdev:
	kfree(pbutton); 

	return ret;
}

static int button_remove(struct platform_device *pdev)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*释放中断*/
	free_irq(pbutton->irq, NULL);

	/*销毁设备文件*/
	device_destroy(pbutton->pcls, MKDEV(pbutton->major, 123));

	/*销毁设备类*/
	class_destroy(pbutton->pcls);
	
	/*注销主设备号*/
	unregister_chrdev(pbutton->major, "button_drv");
	printk("<kernel>unregister major success!\n");

	/*释放堆区空间*/
	kfree(pbutton);

	return 0;
}




/*定义平台驱动对象*/	
static struct platform_driver button_driver = 
{
	.probe		= button_probe,
	.remove		= button_remove,
	.driver		= {.name	= "rk_button", },
	.id_table	= button_id_table, //让驱动匹配多个设备
};


/*入口函数——insmod调用*/
static int __init driver_mod_init(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return platform_driver_register(&button_driver);
}

/*出口函数——rmmod调用*/
static void __exit driver_mod_exit(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	platform_driver_unregister(&button_driver);
}


module_init(driver_mod_init); //告诉内核本模块程序的入口函数名
module_exit(driver_mod_exit);//告诉内核本模块程序的出口函数名
MODULE_LICENSE("GPL"); //遵守开源许可协议



